﻿if (Garmin == undefined) var Garmin = {};
/** Copyright &copy; 2007-2010 Garmin Ltd. or its subsidiaries.
*
* Licensed under the Apache License, Version 2.0 (the 'License')
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* 
* @fileoverview Garmin.MapController Overlays tracks and waypoint data on Google maps.
* @version 1.9
*/
/**
* Accepts Garmin.Series objects and draws them on a Google Map.
* 
* @class Garmin.MapController
* @constructor 
* @param (String) mapString id of element to place map in
*/
Garmin.MapController3 = function (mapString) { }; //just here for jsdoc
Garmin.MapController3 = Class.create();
Garmin.MapController3.prototype = {

    initialize: function (mapString) {
        this.mapElement = $(mapString);
        this.usePositionMarker = true;

        this.polylines = new Array();
        this.markers = new Array();
        this.tracks = new Array();
        this.markerIndex = 0;
        this.options = { mapTypeId: google.maps.MapTypeId.ROADMAP, styles: [
  {
      stylers: [
      { visibility: "simplified" },
      { invert_lightness: true },
      { hue: "#ff00bb" },
      { saturation: 26 },
      { lightness: 21 },
      { gamma: 0.75 }
    ]
  }
]
        };

        this.timeToCheck = false;
        try {
            this.map = new google.maps.Map($(mapString), this.options);
            //this.map.addControl(new GSmallMapControl());
            //this.map.addControl(new GMapTypeControl());
            //new GKeyboardHandler(this.map);
        } catch (e) {
            alert("WARNING: application will not function properly with missing Google script element or invalid Google map key.  Error: " + e);
        }
        window.onUnload = "GUnload()";
    },

    clearOverlays: function() {
        if (this.markers) { for(var i = 0; i < this.markers.length; ++i) { this.markers[i].setMap(null); }; this.markers.clear(); }
        if (this.polylines) { for(var i = 0; i < this.polylines.length; ++i) { this.polylines[i].setMap(null); }; this.polylines.clear(); }
        },

    /** Set the center point and zoom level of the map.
    * @param (Number) Latitude of the center point
    * @param (Number) Longitude of the center point
    * @param (Number) Zoom level
    */
    centerAndScale: function (lat, lon, scale) {
        scale = (scale == null ? 13 : scale);
        this.map.setCenter(new google.maps.LatLng(lat, lon));
        this.map.setZoom(scale);
    },

    /** Draw track on map.
    * @param (Garmin.Track) The track to draw
    * @param (String) Color in RGB Hex format, default: "#ff0000"
    */
    drawTrack: function (series, color) {
        color = (color == null ? "#ffffff" : color);

        // create a smaller version of the whole track
        // create 300 points or so ...
        // Problem is that Google Maps dies when you hit near 500 points, so we have to
        // ensure that we create fewer than that for the track.
        var drawAt = Math.ceil(series.getSamplesLength() / 300);
        var drawnPoints = new Array();

        try {
            // create up to 300 points
            for (var h = 0; h < series.getSamplesLength(); h += drawAt) {
                drawnPoints.push(this.createNearestValidLocationPoint(series, h, -1));
            }
            // create the end point
            drawnPoints.push(this.createNearestValidLocationPoint(series, series.getSamplesLength() - 1, -1));
        } catch (e) {
            alert("GoogleMapControl.drawTrack: " + e.message);
        }

        if (drawnPoints.length > 0) {
            //draw the new smaller version
            var polyline = new google.maps.Polyline({ path: drawnPoints, strokeColor: color, strokeWeight: 2, strokeOpacity: .8 })
            try {
                this.centerAndScale(drawnPoints[0].lat(), drawnPoints[0].lng());
                polyline.setMap(this.map);
                this.polylines.push(polyline);
                this.addStartFinishMarkers(series);
                this.bounds = this.findAZoomLevel(drawnPoints);
                this.setOnBounds(this.bounds);
            } catch (e) { alert("GoogleMapControl.drawTrack, IE error on map.addOverlay(" + polyline + ") err: " + e); }
        }
    },

    /**Creates a GLatLng for the sample in the series closest to the index with a valid location (lat and lon).
    * @param series - The series to search through.
    * @param index - The index to start searching from.
    * @param incDirection - The direction to travel for the search.
    * @return A GLatLng of the nearest valid location sample found.
    */
    createNearestValidLocationPoint: function (series, index, incDirection) {
        var sample = series.findNearestValidLocationSample(index, -1);
        if (sample != null) {
            var sampleLat = sample.getMeasurement(Garmin.Sample.MEASUREMENT_KEYS.latitude).getValue();
            var sampleLon = sample.getMeasurement(Garmin.Sample.MEASUREMENT_KEYS.longitude).getValue();
            return new google.maps.LatLng(sampleLat, sampleLon);
        } else {
            throw new Error("No valid location point in series.");
        }
    },

    /** Draw waypoint on map.
    * @param (Garmin.Series) series containing a waypoint to add to the map
    */
    drawWaypoint: function (series) {
        var sample = series.getSample(0);
        this.centerAndScale(sample.getLatitude(), sample.getLongitude(), 15);
        this.addMarker(sample.getLatitude(), sample.getLongitude());
    },

    /** Calculates minimum bounding box for an set of points.
    * @param (Array) The array of points to find a zoom level for
    */
    findAZoomLevel: function (points) {
        var bounds = new google.maps.LatLngBounds(points[0], points[0]);

        for (var i = 1; i < points.length - 1; i += 3) {
            bounds.extend(points[i]);
        }

        return bounds;
    },

    /** Check the new dimensions of the map, and determine the bounds of the tracks
    * Then set the map to zoom to that bound level
    * @private
    */
    sizeAndSetOnBounds: function () {
        this.setOnBounds(this.bounds);
    },

    /** Set the bounding box on the map.
    * @param (GLatLngBounds) bounding box for the
    */
    setOnBounds: function (bounds) {
        this.map.fitBounds(bounds);
    },

    /** Add an icon to a point.
    * @param {Number} latitude of marker
    * @param {Number} longitude of marker
    */
    addMarker: function (latitude, longitude) {
        this.addMarkerWithIcon(latitude, longitude, Garmin.MapIcons3.getRedIcon());
    },

    /** Adds a marker to the point with the icon specified
    * @param {Number} latitude of marker
    * @param {Number} longitude of marker
    * @param (GIcon) icon to add at the point
    */
    addMarkerWithIcon: function (latitude, longitude, icon) {
        var marker = new google.maps.Marker({ position: new google.maps.LatLng(latitude, longitude), icon: icon });
        this.markers.push(marker);
        marker.setMap(this.map);
        this.markers.push(marker);
    },

    /** Add start and finish markers to a track
    * @param (Garmin.Series) The series to add markers to
    */
    addStartFinishMarkers: function (series) {
        var firstSample = series.getFirstValidLocationSample();
        var lastSample = series.getLastValidLocationSample();
        this.addMarkerWithIcon(firstSample.getLatitude(), firstSample.getLongitude(), Garmin.MapIcons3.getGreenIcon());
        this.addMarkerWithIcon(lastSample.getLatitude(), lastSample.getLongitude(), Garmin.MapIcons3.getRedIcon());
    },

    /** String representation of map.
    * @return (String)
    */
    toString: function () {
        return "Google Based Map Controller, managing " + this.tracks.length + " track(s)";
    }
};

/** Icons used to mark waypoints and POIs on Google maps.  
* 
* @class Garmin.MapIcons
* @constructor 
*/
Garmin.MapIcons3 = function () { }; //just here for jsdoc
Garmin.MapIcons3 = {
    getRedIcon: function () {
        var icon = new google.maps.MarkerImage("http://developer.garmin.com/img/marker_red.png");
        return Garmin.MapIcons3._applyShadowAndStuff(icon);
    },

    getGreenIcon: function () {
        var icon = new google.maps.MarkerImage("http://developer.garmin.com/img/marker_green.png");
        return Garmin.MapIcons3._applyShadowAndStuff(icon);
    },

    _applyShadowAndStuff: function (icon) {
        icon.size = new google.maps.Size(12, 20);
        //icon.shadow = "http://developer.garmin.com/img/marker_shadow.png";
        //icon.shadowSize = new GSize(22, 20);
        icon.anchor = new google.maps.Point(6, 20);
        //icon.infoWindowAnchor = new GPoint(5, 1);
        return icon;
    }
}
